﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.FxCop.Sdk;
using NamedPipe;

namespace BovespaMaintainabilityRules
{
    [BaseAddIn.Rules.DoubleClass("Rule_BovespaVariablesAtSameCodeBlockOneLine")]
    public sealed class Rule_BovespaVariablesAtSameCodeBlockOneLine_FxCop : BaseAddIn.Rules.BaseRuleFXCop
    {
        #region Constructor

        public Rule_BovespaVariablesAtSameCodeBlockOneLine_FxCop() :
            base("BovespaVariablesAtSameCodeBlockOneLine", "BovespaMaintainabilityRules.BovespaMaintainabilityRules", typeof(Rule_BovespaVariablesAtSameCodeBlockOneLine_FxCop).Assembly)
        {
        }

        #endregion

        #region Public Override Methods

        public sealed override ProblemCollection Check(Member member)
        {
            string _namespace;
            string _class;
            string _method;
            int? _lineFirstInstruction = null;
            bool _currentSet = false;
            List<Int32> lineLocalInstructions = new List<Int32>();
            StringBuilder variableList = new StringBuilder();
            
            if (member.NodeType == NodeType.Method)
            {
                Method method = member as Method;

                _namespace = method.DeclaringType.Namespace.Name;
                _class = method.DeclaringType.Name.Name;
                _method = method.Name.Name;

                if (method != null)
                {                    
                    if (method.Locals != null)
                    {
                        foreach (Local local in method.Locals.Where(l => !l.Name.Name.Contains("$")))
                        {
                            //this.VariableList.Add(new VariableFxCop(this.FormatType(local.Type.Name.Name), local.Name.Name));
                            variableList.Append(string.Concat(this.FormatType(local.Type.Name.Name), Atributos.DIVIDE_PROPERTIES, local.Name.Name, Atributos.DIVIDE_VARIABLES));
                        }

                        if (variableList.Length > 0)
                        {
                            if (method.Instructions != null)
                            {                                
                                foreach (Instruction instruction in method.Instructions.Where(i => i.Value is Local &&
                                                                                              i.SourceContext.FileName != null))
                                {                                    
                                    if(!(instruction.Value as Local).Name.Name.Contains("$"))
                                        lineLocalInstructions.Add(instruction.SourceContext.StartLine);
                                }
                                
                                foreach (Instruction instruction in method.Instructions.Where
                                            (
                                                i => !(i.Value is Local) &&
                                                i.SourceContext.FileName != null &&
                                                i.OpCode != OpCode.Ret &&
                                                i.OpCode != OpCode.Nop &&
                                                !lineLocalInstructions.Contains(i.SourceContext.StartLine)
                                            )
                                        )
                                {
                                    _lineFirstInstruction = instruction.SourceContext.StartLine;
                                    break;
                                }
                            }
                        }

                        if (variableList.Length > 0 && _lineFirstInstruction != null)
                        {
                            string varList = variableList.ToString();

                            NamedPipe.Client.ClientConnect clientConnect = new NamedPipe.Client.ClientConnect();
                            clientConnect.ConnectPipeServer(_namespace, _class, string.Concat(_method, Atributos.DIVIDE_PROPERTIES, _lineFirstInstruction.Value), varList.Remove(varList.LastIndexOf(Atributos.DIVIDE_VARIABLES)));
                        }
                    }
                }
            }
            
            return this.Problems;
        }

        #endregion

        #region Private Methods

        private String FormatType(String type)
        {
            int maiorIndice = 0;
            int menorIndice = 0;
            int acentoIndice = 0;
            string auxType = string.Empty;

            type = type.Trim();

            if (type.Contains("Nullable"))
            {
                maiorIndice = type.IndexOf('>');
                menorIndice = type.IndexOf('<');

                type = type.Substring(menorIndice + 1, maiorIndice - menorIndice - 1);
                type = type.Contains('.') ? type.Split('.').LastOrDefault() : type;
                type += '?';

                if (type.Length - 1 > maiorIndice)
                    type = type.Substring(maiorIndice + 1);
            }
            else if (type.Contains("`"))
            {
                maiorIndice = type.IndexOf('>');
                menorIndice = type.IndexOf('<');
                acentoIndice = type.IndexOf('`');

                type = type.Remove(acentoIndice, menorIndice - acentoIndice);
                auxType = type.Substring(menorIndice - 1, maiorIndice - menorIndice - 1);
                type = type.Remove(menorIndice - 1, maiorIndice - menorIndice - 1);

                foreach (String str in auxType.Split(','))
                {
                    type = type.Insert(menorIndice - 1, str.Split('.').LastOrDefault() + ", ");
                }

                type = type.Replace(", >", ">");
            }
            else if (type == "Single")
            {
                type = "Float";
            }

            return type;
        }

        #endregion
    }
}
